--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Commit e606892ff09b2fe41b9ca9561d4f47b000cf8ba8
Parents : 903c75d
Author : Mark Qvist <mark@unsigned.io>
Date : 2021-09-10T21:33:29+02:00
Added file hosting to nodes.
Changes
3 files changed, 103 insertions(+), 8 deletions(-)
Diff
diff --git a/nomadnet/Node.py b/nomadnet/Node.py
index 155d4d7..d4de6a9 100644
--- a/nomadnet/Node.py
+++ b/nomadnet/Node.py
@@ -44,7 +44,6 @@ class Node:
for page in self.servedpages:
request_path = "/page"+page.replace(self.app.pagespath, "")
-
self.destination.register_request_handler(
request_path,
response_generator = self.serve_page,
@@ -55,6 +54,14 @@ class Node:
self.servedfiles = []
self.scan_files(self.app.filespath)
+ for file in self.servedfiles:
+ request_path = "/file"+file.replace(self.app.filespath, "")
+ self.destination.register_request_handler(
+ request_path,
+ response_generator = self.serve_file,
+ allow = RNS.Destination.ALLOW_ALL
+ )
+
def scan_pages(self, base_path):
files = [file for file in os.listdir(base_path) if os.path.isfile(os.path.join(base_path, file)) and file[:1] != "."]
directories = [file for file in os.listdir(base_path) if os.path.isdir(os.path.join(base_path, file)) and file[:1] != "."]
@@ -76,10 +83,10 @@ class Node:
self.scan_files(base_path+"/"+directory)
def serve_page(self, path, data, request_id, remote_identity, requested_at):
- RNS.log("Request "+RNS.prettyhexrep(request_id)+" for: "+str(path), RNS.LOG_VERBOSE)
+ RNS.log("Page request "+RNS.prettyhexrep(request_id)+" for: "+str(path), RNS.LOG_VERBOSE)
file_path = path.replace("/page", self.app.pagespath, 1)
try:
- RNS.log("Serving file: "+file_path, RNS.LOG_VERBOSE)
+ RNS.log("Serving page: "+file_path, RNS.LOG_VERBOSE)
fh = open(file_path, "rb")
response_data = fh.read()
fh.close()
@@ -90,6 +97,22 @@ class Node:
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
return None
+ # TODO: Improve file handling, this will be slow for large files
+ def serve_file(self, path, data, request_id, remote_identity, requested_at):
+ RNS.log("File request "+RNS.prettyhexrep(request_id)+" for: "+str(path), RNS.LOG_VERBOSE)
+ file_path = path.replace("/file", self.app.filespath, 1)
+ file_name = path.replace("/file/", "", 1)
+ try:
+ RNS.log("Serving file: "+file_path, RNS.LOG_VERBOSE)
+ fh = open(file_path, "rb")
+ file_data = fh.read()
+ fh.close()
+ return [file_name, file_data]
+
+ except Exception as e:
+ RNS.log("Error occurred while handling request "+RNS.prettyhexrep(request_id)+" for: "+str(path), RNS.LOG_ERROR)
+ RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
+ return None
def serve_default_index(self, path, data, request_id, remote_identity, requested_at):
RNS.log("Serving default index for request "+RNS.prettyhexrep(request_id)+" for: "+str(path), RNS.LOG_VERBOSE)
diff --git a/nomadnet/NomadNetworkApp.py b/nomadnet/NomadNetworkApp.py
index 4b9dace..7be5ccf 100644
--- a/nomadnet/NomadNetworkApp.py
+++ b/nomadnet/NomadNetworkApp.py
@@ -54,6 +54,8 @@ class NomadNetworkApp:
self.pagespath = self.configdir+"/storage/pages"
self.filespath = self.configdir+"/storage/files"
+ self.downloads_path = os.path.expanduser("~/Downloads")
+
if not os.path.isdir(self.storagepath):
os.makedirs(self.storagepath)
@@ -254,6 +256,10 @@ class NomadNetworkApp:
value = self.config["client"].as_bool(option)
self.enable_client = value
+ if option == "downloads_path":
+ value = self.config["client"]["downloads_path"]
+ self.downloads_path = os.path.expanduser(value)
+
if option == "user_interface":
value = value.lower()
if value == "none":
@@ -391,6 +397,7 @@ destination = file
enable_client = yes
user_interface = text
+downloads_path = ~/Downloads
[textui]
diff --git a/nomadnet/ui/textui/Browser.py b/nomadnet/ui/textui/Browser.py
index 6e2befe..fbab06e 100644
--- a/nomadnet/ui/textui/Browser.py
+++ b/nomadnet/ui/textui/Browser.py
@@ -1,4 +1,5 @@
import RNS
+import os
import time
import urwid
import nomadnet
@@ -54,6 +55,7 @@ class Browser:
self.response_progress = 0
self.response_size = None
self.response_transfer_size = None
+ self.saved_file_name = None
self.page_data = None
self.displayed_page_data = None
self.auth_identity = auth_identity
@@ -248,9 +250,16 @@ class Browser:
raise ValueError("Malformed URL")
if destination_hash != None and path != None:
- self.set_destination_hash(destination_hash)
- self.set_path(path)
- self.load_page()
+ if path.startswith("/file/"):
+ if destination_hash == self.destination_hash:
+ self.download_file(destination_hash, path)
+ else:
+ RNS.log("Cannot request file download from a node that is not currently connected.", RNS.LOG_ERROR)
+ RNS.log("The requested URL was: "+str(url), RNS.LOG_ERROR)
+ else:
+ self.set_destination_hash(destination_hash)
+ self.set_path(path)
+ self.load_page()
def set_destination_hash(self, destination_hash):
if len(destination_hash) == RNS.Identity.TRUNCATED_HASHLENGTH//8:
@@ -268,6 +277,33 @@ class Browser:
self.timeout = timeout
+ def download_file(self, destination_hash, path):
+ if self.link != None and self.link.destination.hash == self.destination_hash:
+ # Send the request
+ self.status = Browser.REQUESTING
+ self.response_progress = 0
+ self.response_size = None
+ self.response_transfer_size = None
+ self.saved_file_name = None
+
+ self.update_display()
+ receipt = self.link.request(
+ path,
+ data = None,
+ response_callback = self.file_received,
+ failed_callback = self.request_failed,
+ progress_callback = self.response_progressed
+ )
+
+ if receipt:
+ self.last_request_receipt = receipt
+ self.last_request_id = receipt.request_id
+ self.status = Browser.REQUEST_SENT
+ self.update_display()
+ else:
+ self.link.teardown()
+
+
def load_page(self):
load_thread = threading.Thread(target=self.__load)
load_thread.setDaemon(True)
@@ -278,7 +314,7 @@ class Browser:
# If an established link exists, but it doesn't match the target
# destination, we close and clear it.
if self.link != None and self.link.destination.hash != self.destination_hash:
- self.link.close()
+ self.link.teardown()
self.link = None
# If no link to the destination exists, we create one.
@@ -327,6 +363,8 @@ class Browser:
self.response_progress = 0
self.response_size = None
self.response_transfer_size = None
+ self.saved_file_name = None
+
self.update_display()
receipt = self.link.request(
@@ -383,6 +421,30 @@ class Browser:
except Exception as e:
RNS.log("An error occurred while handling response. The contained exception was: "+str(e))
+
+ def file_received(self, request_receipt):
+ try:
+ file_name = request_receipt.response[0]
+ file_data = request_receipt.response[1]
+ file_destination = self.app.downloads_path+"/"+file_name
+
+ counter = 0
+ while os.path.isfile(file_destination):
+ counter += 1
+ file_destination = self.app.downloads_path+"/"+file_name+"."+str(counter)
+
+ fh = open(file_destination, "wb")
+ fh.write(file_data)
+ fh.close()
+
+ self.saved_file_name = file_destination.replace(self.app.downloads_path+"/", "", 1)
+ self.status = Browser.DONE
+ self.response_progress = 0
+
+ self.update_display()
+ except Exception as e:
+ RNS.log("An error occurred while handling file response. The contained exception was: "+str(e))
+
def request_failed(self, request_receipt=None):
if request_receipt != None:
@@ -453,7 +515,10 @@ class Browser:
elif self.status == Browser.RECEIVING_RESPONSE:
return "Receiving response..."
elif self.status == Browser.DONE:
- return "Done"+stats_string
+ if self.saved_file_name == None:
+ return "Done"+stats_string
+ else:
+ return "Saved "+str(self.saved_file_name)+stats_string
elif self.status == Browser.DISCONECTED:
return "Disconnected"
else:
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────